package com.song.boot.springstudy.netty.websocket.ws1;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDate;
import java.util.concurrent.ConcurrentHashMap;

@ChannelHandler.Sharable
@Slf4j
public class WebSocketFrameHandler extends SimpleChannelInboundHandler<WebSocketFrame> {
    
    // 连接管理器（线程安全）
    private static final ConcurrentHashMap<String, Channel> channelMap = new ConcurrentHashMap<>();
    
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) {
        // 1. 文本消息处理
        if (frame instanceof TextWebSocketFrame) {
            handleTextFrame(ctx, (TextWebSocketFrame) frame);
        } 
        // 2. 心跳检测处理
        else if (frame instanceof PingWebSocketFrame) {
            ctx.writeAndFlush(new PongWebSocketFrame(frame.content().retain()));
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        // 新连接注册
        String channelId = ctx.channel().id().asLongText();
        channelMap.put(channelId, ctx.channel());
        log.info("Client connected: {}", channelId);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        // 连接断开清理
        String channelId = ctx.channel().id().asLongText();
        channelMap.remove(channelId);
        log.warn("Connection lost: {}", channelId);
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
        // 3. 心跳超时检测
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent e = (IdleStateEvent) evt;
            if (e.state() == IdleState.READER_IDLE) {
                log.warn("Heartbeat timeout, closing connection: {}", ctx.channel().id());
                ctx.close();
            }
        }
    }

    private void handleTextFrame(ChannelHandlerContext ctx, TextWebSocketFrame frame) {
        String text = frame.text();
        // 处理心跳特殊消息
        if ("HEARTBEAT".equals(text)) {
            ctx.writeAndFlush(new TextWebSocketFrame("HEARTBEAT_ACK"));
            return;
        }
        // 其他业务消息处理... channel 隔离  不然串了
        String channelId = ctx.channel().id().asLongText();
        Channel channel = channelMap.get(channelId);
        channel.writeAndFlush(new TextWebSocketFrame(LocalDate.now() + text+"<><>自动回复客户端信息"));
    }
}